#pragma once

#include <map>
#include <afxmt.h>
#include "HttpClient.h"
#include "Travian.h"
#include "TravianAutoTask.h"

//
// sent to UI window to notify Tasks parameter set result, task executing state, or whether entire schedule finished, when task finish action is not exit or shutdown.
//
#define WM_USERMSG_TASK_SETPARAM_FINISHED	( WM_APP + 108 )	// wParam indicates whether tasks parameter set successful(1) or failed(0). LPARAM is the pointer of returned Tasks object, user needs to delete this object if he doesn't use it. This message only sent when set tasks file name parameter instead of other parameters. 
#define WM_USERMSG_TASK_EXECSTATE			( WM_APP + 109 )	// wParam is the task order index, numbered from 0, LPARAM is the executing state.
#define WM_USERMSG_SCHEDULE_FINISHED		( WM_APP + 110 )	// wParam is 0, while lparam is the schedule thread id.
#define WM_USERMSG_INITIALIZATION_FINISHED	( WM_APP + 111 )	// 

using namespace std;
using namespace System::EventLog;
using namespace System::Internet;

//namespace Travian
//{

	enum eTravianTaskFinishAction {  
		E_ACTION_NONE = 0, 
		E_ACTION_SHUTDOWN = 1, 
		E_ACTION_EXIT = 2 
	};

	enum eShutDown {
		E_SD_SHUTDOWN = 0,
		E_SD_LOGOFF = 1,
		E_SD_RESTART = 2
	};

	class CTravianTaskSchedule: public CEventWrapper
	{
	public:
		CTravianTaskSchedule(void) throw(...) ;
		~CTravianTaskSchedule(void);
		void Cleanup();
		void SetEventLog(CEventLog* pEvtLog)	{ m_pEvtLog = pEvtLog; m_http.SetEventLog(pEvtLog);};

		bool Init() {
			if (!m_http.Init()) {
				LOGERR( _T("Init CHttpClient failed(create IWebBrowser2).") );
				return false;
			}
			return true;
		};
		bool SetSvr(LPCTSTR lpszSvr) { m_sSvr = lpszSvr; return true;};
		bool SetUserPwd(LPCTSTR lpszUser, LPCTSTR lpszPwd) {
			m_sUsr = lpszUser;
			m_sPwd = lpszPwd;
			return true;
		};

		bool SetTasks(LPCTSTR lpszTaskFileName) {
			CTravianTask::ClearTasks(m_tasks);
			CTravianTask::ClearTasks(m_tasksFailed);
			if (!CTravianTask::GetTasks(lpszTaskFileName, m_tasks, *m_pEvtLog) || m_tasks.size()<1)		
			{
				LOGERR(_T("Parse task file failed"));
				return false;
			}
			return true;
		};
		bool SetTasks(Tasks& ts) {
			CTravianTask::ClearTasks(m_tasks);
			CTravianTask::ClearTasks(m_tasksFailed);
			m_tasks = CTravianTask::CloneTasks(ts);
			return true;
		};
		bool SetAttackTasks(Tasks& ts) {
			AfxOutputDebugString("-- SetAttackTasks --\n");
			m_tasksAttack.insert(m_tasksAttack.end(),ts.begin(),ts.end());
			AfxOutputDebugString("-- m_tasksAttack.size() = %d --\n",m_tasksAttack.size());
			return true;
		};
		const Tasks& GetTasks() { return m_tasks; };
		void ClearTasks() { CTravianTask::ClearTasks(m_tasks); CTravianTask::ClearTasks(m_tasksFailed);};
		void ClearAllAttackTasks() {
			AfxOutputDebugString("-- ClearAllAttackTasks() --\n");
			AfxOutputDebugString("---- m_tasksAttack.size() = %d --\n",m_tasksAttack.size());
			CTravianTask::ClearTasks(m_tasksAttack);
		};
		bool SetTaskFinishAction(eTravianTaskFinishAction eAction) { m_eAction = eAction; return true;};
		bool SetWnd2Notify(HWND hWnd) { m_hWnd2Notify = hWnd; return true;};
		HWND GetWnd2Notify() { return m_hWnd2Notify; };
		bool Start();
		bool StartAttackTimer( UINT uID, UINT uElapse );
		void EreaseAttackTimer( UINT uID );
		void EraseAttackTask(UINT nID) {
			AfxOutputDebugString("-- EraseAttackTask(%d) --\n",nID);
			AfxOutputDebugString("---- m_nTimerAttackTask[nID] = (%d,%d) \n",m_nTimerAttackTask[nID].first,m_nTimerAttackTask[nID].second);
			AfxGetMainWnd()->KillTimer(m_nTimerAttackTask[nID].second);
// 			m_nTimerAttackTask.erase(m_nTimerAttackTask.begin()+nID);
// 			//delete m_tasksAttack[nID].second;
// 			m_tasksAttack.erase(m_tasksAttack.begin()+nID);
		}
		void KillAllAttackTimer() {
			AfxOutputDebugString("-- KillAllAttackTimer --\n");
			AfxOutputDebugString("---- m_nTimerAttackTask.size() = %d --\n",m_nTimerAttackTask.size());
			vector<pair<UINT,UINT_PTR>>::iterator t;
			for( t=m_nTimerAttackTask.begin() ; t!=m_nTimerAttackTask.end() ; t++ )
				AfxGetMainWnd()->KillTimer(t->second);
			m_nTimerAttackTask.clear();
		};
		void KillTimers() {
			AfxOutputDebugString("-- KillTimers() %d-%d --\n",m_nTimerTask,m_nTimerFailedTask);
			::KillTimer(NULL, m_nTimerTask);
			::KillTimer(NULL, m_nTimerFailedTask);

			m_bRunning = false;
		};

		void GetAttackDateStr(CString &sAttackDate) const;
		CHttpClient &GetHttp() { return m_http; }


	public:
// 		static void CALLBACK EXPORT TimerProc(
		void CALLBACK EXPORT TimerProc(
			HWND hWnd,      // handle of CWnd that called SetTimer
			UINT nMsg,      // WM_TIMER
			UINT nIDEvent,  // timer identification
			DWORD dwTime    // system time
			);
		void ShutDown(eShutDown eSD);


	protected:
		static CString			GetURLLogOut()				{ return CString(TRAVIAN_URL_LOGOUT);};

		bool LogOut();

		UINT RetryFailedTasks(void);	
		UINT ExecTasks(void);
		void ExecAttackTasks(UINT nIdx);
		bool FireTask(CTravianTask& task, bool bRecursive=false);
		bool ModifyDeltaTime(UINT nTaskInd);
		bool ModifyTime(UINT nTaskInd);
		void UpdateListItem(UINT nTaskID, CTravianTask *pTask) const;
		UINT UpdateTaskTimer();

	protected:
		static map<CTravianTaskSchedule*, int>	m_mapTTSObjPtrs;	// all CTravianTaskSchedule objects pointers
		static CCriticalSection					m_csTTSObjPtrs;		// threads sync object for m_mapTTSObjPtrs
		UINT_PTR								m_nTimerTask;

	protected:
		CString									m_sSvr;
		eTravianTaskFinishAction				m_eAction;
		bool									m_bRunning;
		HWND									m_hWnd2Notify;		// hwnd of window which to be notified of finished message

		CHttpClient								m_http;
		Tasks									m_tasks;
		Tasks									m_tasksFailed;
		Tasks									m_tasksAttack;		// Tasks for attack alert

		CString									m_sUsr;
		CString									m_sPwd;

		UINT_PTR								m_nTimerKeepLogin;
		UINT_PTR								m_nTimerFailedTask;
		vector<pair<UINT,UINT_PTR>>				m_nTimerAttackTask;
	};	

//};